package com.gofaraway.service.juc;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 电商网站比价需求分析：
 * 1. 需求说明：
 * a. 同一款产品，同时搜索出同款产品在各大电商平台的售价
 * 2. 输出返回：
 * a. 出来结果希望是同款产品的在不同地方的价格清单列表，返回一个List<String>
 * 例如：《Mysql》 in jd price is 88.05  《Mysql》 in taobao price is 90.43
 * 3. 解决方案，对比同一个产品在各个平台上的价格，要求获得一个清单列表
 * a. step by step，按部就班，查完淘宝查京东，查完京东查天猫....
 * b. all in，万箭齐发，一口气多线程异步任务同时查询
 *
 * @author ChenPeng
 * @Date 2024/3/26 20:09
 */
public class CompletableFutureMallDemo {

    static List<NetMall> list = Arrays.asList(new NetMall("jd"), new NetMall("taobao"), new NetMall("dangdang"));


    public static void main(String[] args) {
        /**
         * 采用step by setp方式查询
         * 《masql》in jd price is 110.11
         * 《masql》in taobao price is 109.32
         * 《masql》in dangdang price is 109.24
         * ------costTime: 3094 毫秒
         */
        long startTime = System.currentTimeMillis();
        List<String> list1 = getPrice(list, "mysql");
        for (String element : list1) {
            System.out.println(element);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("------costTime: " + (endTime - startTime) + " 毫秒");


        System.out.println("---------------------------------------------------------------");

        long startTime2 = System.currentTimeMillis();
        List<String> list2 = getPriceByCompletableFuture(list, "mysql");
        for (String element : list2) {
            System.out.println(element);
        }
        long endTime2 = System.currentTimeMillis();
        System.out.println("------costTime: " + (endTime2 - startTime2) + " 毫秒");

    }

    /**
     * step by step
     *
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPrice(List<NetMall> list, String productName) {
        //《Mysql》 in jd price is 88.05
        return list.stream()
                .map(netMall ->
                        String.format("《" + productName + "》" + "in %s price is %.2f", netMall.getNetMallName(), netMall.calcPrice(productName)))
                .collect(Collectors.toList());
    }



    /**
     * getPriceByCompletableFuture all in
     *
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPriceByCompletableFuture(List<NetMall> list, String productName) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        try {
            return list.stream()
                    .map(netMall ->
                            CompletableFuture.supplyAsync(() ->
                                    String.format("《" + productName + "》" + "in %s price is %.2f", netMall.getNetMallName(), netMall.calcPrice(productName)), executorService))
                    //注意：不能直接map 否则并发失效
                    .collect(Collectors.toList())
                    .stream()
                    .map(CompletableFuture::join)
                    .collect(Collectors.toList());
        } finally {
            //关闭线程池
            executorService.shutdown();
        }

    }

}

@AllArgsConstructor
@NoArgsConstructor
@Data
class NetMall {

    private String netMallName;

    /**
     * 获取价格方法
     *
     * @param productName
     * @return
     * @throws InterruptedException
     */
    public double calcPrice(String productName)   {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
    }
}